"""
fetch nobel physics laureates from official website
"""
import re
import requests
from datetime import datetime
from bs4 import BeautifulSoup
import xlsxwriter


def list_laureates_by_years():
    """
    list years of nobel physics
    :return:
    """
    url = "https://www.nobelprize.org/prizes/lists/all-nobel-prizes-in-physics/"
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "html.parser")
    all_laureates = {}
    for row in soup.find_all("h3"):
        href = row.find('a')
        if href:
            year = re.findall(r'\d{4}', href.text)[0]
            laureate = get_laureates_of_year(year)
            if laureate:
                all_laureates[year] = laureate
    return all_laureates


def get_laureates_of_year(year):
    """
    list laureates of year
    :param year:
    :return:
    """
    laureates_of_year = []
    url = "https://www.nobelprize.org/prizes/physics/" + str(year) + "/summary/"
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "html.parser")
    for figure in soup.find_all('figure', class_="list-laureate"):
        link = figure.find('h3').find('a')
        _laureate = {"link": link.get('href'), "name": link.text.strip()}
        detail = get_laureate(link.get('href'))
        _laureate.update(detail)
        laureates_of_year.append(_laureate)
        print(_laureate)
    return laureates_of_year


def get_laureate(url):
    """
    get detail of laureate
    :param url:
    :return:
    """
    detail = {}
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "html.parser")
    born_text = soup.find('p', class_='born-date').text;
    match = re.search(r"Born:\s*(?P<year>[^,]+),\s*(?P<city>[^,]+),\s*(?P<country>.+)$", born_text)
    # born
    detail['birth'] = parse_date(match.group('year'))
    detail['birth_city'] = match.group('city').strip()
    detail['birth_country'] = match.group('country').strip()
    # if died
    dead_text = soup.find('p', class_='dead-date')
    if dead_text:
        dead_text_text = dead_text.text.strip()
        try:
            match = re.search(r"Died:\s*(?P<year>[^,]+),\s*(?P<city>[^,]+),\s*(?P<country>.+)$", dead_text_text)
            # born
            detail['died'] = parse_date(match.group('year'))
            detail['died_city'] = match.group('city').strip()
            detail['died_country'] = match.group('country').strip()
        except:
            match = re.search(r"Died:\s*(?P<year>[^,]+)", dead_text_text)
            detail['died'] = parse_date(match.group('year'))
    # other data
    other_text = soup.find('div', class_='content').text
    try:
        detail.update(format_affiliation(re.search(r"Affiliation at the time of the award:\n(.+)\n", other_text).group(1)))
    except:
        detail['affiliation'] = 'None'
    try:
        detail['motivation'] = re.search(r'Prize motivation: “(.+)”', other_text).group(1)
    except:
        detail['motivation'] = re.search(r'Prize motivation:\s+(.*)', other_text).group(1)

    # work detail
    work_texts = soup.find('div', class_='description').find_all('p')
    work = ""
    for p in work_texts:
        pt = p.text.strip();
        if len(pt) > 0:
            work += "<p>"
            work += pt
            work += "</p>"

    if len(work) > 0:
        detail['work'] = work

    return detail


def parse_date(date_str):
    date_formats = [
        '%d %B %Y',
        '%Y'
    ]
    for date_format in date_formats:
        try:
            return datetime.strptime(date_str, date_format).date()
        except ValueError:
            pass
    return None


def write_to_excel(years, filename):
    # Create a workbook and add a worksheet.
    workbook = xlsxwriter.Workbook(filename)
    sheet = workbook.add_worksheet("Physics")
    # Start from the first cell. Rows and columns are zero indexed.
    sheet.write(0, 0, 'Year')
    sheet.write(0, 1, 'Name')
    sheet.set_column(1, 1, width=25)
    sheet.write(0, 2, 'Birth')
    sheet.set_column(2, 2, width=12)
    sheet.write(0, 3, 'Birth Country')
    sheet.set_column(3, 3, width=40)
    sheet.write(0, 4, 'Status')
    sheet.set_column(4, 4, width=12)
    sheet.write(0, 5, 'Affiliation')
    sheet.set_column(5, 5, width=60)
    sheet.write(0, 6, 'Affiliation Country')
    sheet.set_column(6, 6, width=12)
    sheet.write(0, 7, 'Motivation')
    sheet.set_column(7, 7, width=80)
    sheet.write(0, 8, 'Work')
    sheet.set_column(8, 8, width=80)
    row = 1
    for year in years:
        laureates_of_year = years.get(year)
        for laureate in laureates_of_year:
            sheet.write(row, 0, year)
            sheet.write_url(row, 1, laureate.get('link'), string=laureate.get('name'))
            sheet.write(row, 2, laureate.get('birth').strftime("%Y-%m-%d"))
            sheet.write(row, 3, format_country(laureate.get('birth_country')))
            sheet.write(row, 4, 'Deceased' if laureate.get('died') else '')
            sheet.write(row, 5, laureate.get('affiliation'))
            sheet.write(row, 6, laureate.get('affiliation_country'))
            sheet.write(row, 7, laureate.get('motivation'))
            sheet.write(row, 8, laureate.get('work'))
            row += 1;

    workbook.close()


def format_country(country_text):
    if country_text.endswith('USA'):
        return 'USA'
    if country_text.startswith('the '):
        return country_text[4:]
    try:
        match = re.search(r',\s*([\w\s]+)\)', country_text)
        return match.group(1).strip()
    except:
        pass
    return country_text


def format_affiliation(affiliation_text):
    affiliations = affiliation_text.split(';')
    affiliation = affiliations[len(affiliations) - 1]
    match = re.search(r'^(.*),\s+([\w]+),\s+([\w]+)$', affiliation.strip())
    school_name = match.group(1).strip()
    state = format_country(match.group(3).strip())
    return {"affiliation": school_name, "affiliation_country": state}


if __name__ == "__main__":
    laureates = list_laureates_by_years()
    # laureates = {"1943": get_laureates_of_year(1964)}
    #print(laureates)
    write_to_excel(laureates, "physics.xlsx")